package com.hxy.security;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import javax.annotation.Resource;

// 启用Security配置
@EnableWebSecurity
@Configuration
// 启用权限注解配置：启用全局方法
@EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true, prePostEnabled = true)
public class SecurityConfigure extends WebSecurityConfigurerAdapter {

    @Resource
    AuthFailHandler authFailHandler;

    @Resource
    AccessDeniedsHandler accessDeniedsHandler;

    @Resource
    AuthenticationEntryPointHandler authenticationEntryPointHandler;

    @Resource
    AuthSuccessHandler authSuccessHandler;

    /**
     * 1.请求被拦截之后，先判断请求路径要执行的操作；
     * 2.如果不是login,调用rbacConfig中的方法，判断是否可以登录；
     * 3.返回false，抛出异常；
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 使用form表单进行登录
        http.formLogin()
                .loginProcessingUrl("/login")
                .usernameParameter("uname")
                .passwordParameter("pwd")
                .failureHandler(authFailHandler)    // 认证失败处理器
                .successHandler(authSuccessHandler) // 认证成功处理器
                .permitAll()                        // 允许访问
                .and()
                .authorizeRequests()                // 认证请求
                //.antMatchers("/**")
                // .permitAll()
                .anyRequest()
                // 是否可以访问：true可以访问，false禁止访问
                // @bean对象名称.方法：根据方法的返回值判断是否可以访问
                .access("@rbacConfig.hasPermission(authentication,request)")
                //.anyRequest()         // 所有请求：最后
                //.authenticated()      // 需要认证
                .and()
                .exceptionHandling()                        // 异常处理器
                .accessDeniedHandler(accessDeniedsHandler)  // 权限：访问被拒绝：已认证的用户访问资源时，权限不足异常
                .authenticationEntryPoint(authenticationEntryPointHandler) // 权限：匿名用户访问无权限资源异常
                .and()
                // 跨域请求
                .cors()
                .and()
                .csrf().disable();
    }


    @Resource
    AuthUserConfigure authUserConfigure;

    /**
     * 配置认证方式
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 添加用户
        /*auth.inMemoryAuthentication().passwordEncoder(new MyPasswordEncoder())
                .withUser("zhangsan").password("123aaa").roles("ADMIN");*/

        auth.userDetailsService(authUserConfigure)
                .passwordEncoder(new BCryptPasswordEncoder());
    }
}
